#include "mainwindow.h"
#include "ui_mainwindow.h"

const int STARTX = 300;
const int STARTY = 30;
const int RECTX = 40;
const int RECTY = 40;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow), n(-1), drawed(true)
{

    ui->setupUi(this);

    ui->NInput->setPlaceholderText("5");
    ui->StartInput->setPlaceholderText("0,0");
    ui->EndInput->setPlaceholderText("4,4");

    ui->pushButton->setVisible(false);

    ui->NextButton->setVisible(false);

    ui->LastButton->setVisible(false);
}

MainWindow::~MainWindow()
{
    delete ui;
}

Pair<int, int> GetRectMid(int n, int x, int y) {
    return MakePair(STARTX + (((9 - n) >> 1) + x) * RECTX + (RECTX >> 1),
                STARTY + (((9 - n) >> 1) + y) * RECTY + (RECTY >> 1)
                );
}

void MainWindow::paintEvent(QPaintEvent *) {
    if (n == -1 || drawed) {
        return;
    }
    drawed = true;
    QPainter p(this);

    // 清除之前画的内容
    p.eraseRect(QRect(STARTX, STARTY, STARTX + RECTX * 9, STARTY + RECTY * 9));

    for (int i = 0; i < 9; i++) {
        if (i < ((9 - n) >> 1)) {
            continue;
        }
        if (i > ((9 - n) >> 1) + n - 1) {
            continue;
        }
        for (int j = 0; j < 9; j++) {
            if (j < ((9 - n) >> 1)) {
                continue;
            }
            if (j > ((9 - n) >> 1) + n - 1) {
                continue;
            }
            p.drawRect(QRect(STARTX + i * RECTX, STARTY + j * RECTY, RECTX, RECTY));
        }
    }
    if (this->paths.IsEmpty()) {
        if (path.q.IsEmpty()) return;
        auto q = path.q;
        Pair<int, int> pos = GetRectMid(n, q.Front().first, q.Front().second), pos2;
        q.Pop();
        // 画起点
        p.setPen(QPen(Qt::red,15));
        p.drawPoint(QPoint(pos.first, pos.second));
        p.setPen(QPen(Qt::red, 5));
        while (!q.IsEmpty()) {
            // 画线
            pos2 = GetRectMid(n, q.Front().first, q.Front().second);
            q.Pop();
            p.drawLine(QPoint(pos.first, pos.second), QPoint(pos2.first, pos2.second));
            pos = pos2;
        }
        // 画终点
        p.setPen(QPen(Qt::red, 15));
        p.drawPoint(QPoint(pos.first, pos.second));
    }
    else {
        auto q = paths[index].q;
        Pair<int, int> pos = GetRectMid(n, q.Front().first, q.Front().second), pos2;
        q.Pop();
        // 画起点
        p.setPen(QPen(Qt::red,15));
        p.drawPoint(QPoint(pos.first, pos.second));
        p.setPen(QPen(Qt::red, 5));
        while (!q.IsEmpty()) {
            // 画线
            pos2 = GetRectMid(n, q.Front().first, q.Front().second);
            q.Pop();
            p.drawLine(QPoint(pos.first, pos.second), QPoint(pos2.first, pos2.second));
            pos = pos2;
        }
        // 画终点
        p.setPen(QPen(Qt::red, 15));
        p.drawPoint(QPoint(pos.first, pos.second));
    }
}

// 检查n是否合法
bool CheckNInput(QString str) {
    str = str.simplified();
    if (str.length() != 1 || !str.at(0).isDigit()) {
        return false;
    }
    return true;
}

// 检查x,y是否合法
bool CheckPairInput(QString str) {
    str = str.remove(QRegExp("\\s")); // 去所有空格
    if (str.length() != 3 || !str.at(0).isDigit() || !(str.at(1).toLatin1() == ',') || !str.at(2).isDigit()) {
        return false;
    }
    return true;
}

void MainWindow::on_BfsButton_clicked()
{
    // 检测输入是否合法
    if (!CheckNInput(ui->NInput->text()) || !CheckPairInput(ui->StartInput->text()) || !CheckPairInput(ui->EndInput->text())) {
        QMessageBox::critical(this, "Error", "输入不合法！");
        return;
    }
    this->n = ui->NInput->text().at(0).toLatin1() ^ 48;
    this->start = MakePair(ui->StartInput->text().at(0).toLatin1() ^ 48, ui->StartInput->text().at(2).toLatin1() ^ 48);
    this->end = MakePair(ui->EndInput->text().at(0).toLatin1() ^ 48, ui->EndInput->text().at(2).toLatin1() ^ 48);
    if (this->start.first >= n || this->start.first < 0 || this->start.second >= n || this->start.second < 0 ||
            this->end.first >= n || this->end.first < 0 || this->end.second >= n || this->end.second < 0) {
        QMessageBox::critical(this, "Error", "输入不合法！");
        return;
    }
    ui->NextButton->setVisible(false);
    ui->LastButton->setVisible(false);
    this->paths = Vector<Path>();
    this->path = CircuitBoard(n).GetBfsPath(this->start, this->end);
    drawed = false;
    this->update();
}

void MainWindow::on_DfsButton_clicked()
{
    // 检测输入是否合法
    if (!CheckNInput(ui->NInput->text()) || !CheckPairInput(ui->StartInput->text()) || !CheckPairInput(ui->EndInput->text())) {
        QMessageBox::critical(this, "Error", "输入不合法!");
        return;
    }
    this->n = ui->NInput->text().at(0).toLatin1() ^ 48;
    if (this->n > 4) {
        QMessageBox::information(this, "提示", "情况过多,DFS难以显示!");
        return;
    }
    this->start = MakePair(ui->StartInput->text().at(0).toLatin1() ^ 48, ui->StartInput->text().at(2).toLatin1() ^ 48);
    this->end = MakePair(ui->EndInput->text().at(0).toLatin1() ^ 48, ui->EndInput->text().at(2).toLatin1() ^ 48);
    if (this->start.first >= n || this->start.first < 0 || this->start.second >= n || this->start.second < 0 ||
            this->end.first >= n || this->end.first < 0 || this->end.second >= n || this->end.second < 0) {
        QMessageBox::critical(this, "Error", "输入不合法！");
        return;
    }
    ui->NextButton->setVisible(true);
    ui->LastButton->setVisible(true);
    this->path = Path();
    this->paths = CircuitBoard(n).GetDfsPaths(this->start, this->end);
    this->index = 0;
    drawed = false;
    this->update();
}

void MainWindow::on_NextButton_clicked()
{
    if (this->index + 1 < this->paths.Size()) {
        this->index++;
    }
    this->update();
    drawed = false;
}

void MainWindow::on_LastButton_clicked()
{
    if (this->index - 1 >= 0) {
        this->index--;
    }
    drawed = false;
    this->update();
}
